package com.platform.dao.base;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.persistence.Query;

import org.apache.commons.lang.StringUtils;
import org.springframework.util.Assert;

import com.platform.internal.Page;

/**
 * 封装SpringSide扩展功能的Hibernat DAO泛型基类.
 * 
 * 扩展功能包括分页查询,按属性过滤条件列表查询. 可在Service层直接使用,也可以扩展泛型DAO子类使用,见两个构造函数的注释.
 * 
 * @param <T>
 *            DAO操作的对象类型
 * @param <PK>
 *            主键类型
 * 
 * @author calvin
 */
//TODO: improve this. By Wf
public class HibernateDAO<T, PK extends Serializable> extends SimpleHibernateDAO<T, PK> {
	/**
	 * 用于Dao层子类的构造函数. 通过子类的泛型定义取得对象类型Class. eg. public class UserDao extends
	 * HibernateDao<User, Long>{ }
	 */
	public HibernateDAO() {
		super();
	}

	/**
	 * 用于省略Dao层, Service层直接使用通用HibernateDao的构造函数. 在构造函数中定义对象类型Class.
	 */
	public HibernateDAO(final Class<T> entityClass) {
		super(entityClass);
	}

	// -- 分页查询函数 --//

//	/**
//	 * 分页获取全部对象.
//	 */
//	public Page<T> getAll(final Page<T> page) {
//		return this.findPage(page);
//	}

	/**
	 * 按HQL分页查询.
	 * 
	 * @param page
	 *            分页参数. 注意不支持其中的orderBy参数.
	 * @param ql
	 *            ql语句.
	 * @param values
	 *            数量可变的查询参数,按顺序绑定.
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
	 */
	@SuppressWarnings("unchecked")
	public Page<T> findPage(final Page<T> page, final String ql, final Object... values) {
		Assert.notNull(page, "page不能为空");

		final Query q = this.createQuery(ql, values);

		if (page.isAutoCount()) {
			final long totalCount = this.countQlResult(ql, values);
			page.setTotalCount(totalCount);
		}

		this.setPageParameterToQuery(q, page);

		final List<T> result = q.getResultList();
		page.setResult(result);
		
		return page;
	}

	/**
	 * 按QL分页查询.
	 * 
	 * @param page
	 *            分页参数. 注意不支持其中的orderBy参数.
	 * @param ql
	 *            ql语句.
	 * @param values
	 *            命名参数,按名称绑定.
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
	 */
	@SuppressWarnings("unchecked")
	public Page<T> findPage(final Page<T> page, final String ql, final Map<String, ?> values) {
		Assert.notNull(page, "page不能为空");

		final Query query = this.createQuery(ql, values);

		if (page.isAutoCount()) {
			final long totalCount = this.countQlResult(ql, values);
			page.setTotalCount(totalCount);
		}
		this.setPageParameterToQuery(query, page);

		page.setResult(query.getResultList());
		
		return page;
	}

//	/**
//	 * 按Criteria分页查询.
//	 * 
//	 * @param page
//	 *            分页参数.
//	 * @param criterions
//	 *            数量可变的Criterion.
//	 * 
//	 * @return 分页查询结果.附带结果列表及所有查询输入参数.
//	 */
//	@SuppressWarnings("unchecked")
//	public Page<T> findPage(final Page<T> page, final Criterion... criterions) {
//		Assert.notNull(page, "page不能为空");
//
//		final Criteria c = this.createCriteria(criterions);
//
//		if (page.isAutoCount()) {
//			final long totalCount = this.countCriteriaResult(c);
//			page.setTotalCount(totalCount);
//		}
//
//		this.setPageParameterToCriteria(c, page);
//
//		final List result = c.list();
//		page.setResult(result);
//		return page;
//	}

	/**
	 * 设置分页参数到Query对象,辅助函数.
	 */
	protected Query setPageParameterToQuery(final Query q, final Page<T> page) {

		Assert.isTrue(page.getPageSize() > 0, "Page Size must larger than zero");

		// hibernate的firstResult的序号从0开始
		q.setFirstResult(page.getFirst() - 1);
		q.setMaxResults(page.getPageSize());
		return q;
	}
//
//	/**
//	 * 设置分页参数到Criteria对象,辅助函数.
//	 */
//	protected Criteria setPageParameterToCriteria(final Criteria c, final Page<T> page) {
//
//		Assert.isTrue(page.getPageSize() > 0, "Page Size must larger than zero");
//
//		// hibernate的firstResult的序号从0开始
//		c.setFirstResult(page.getFirst() - 1);
//		c.setMaxResults(page.getPageSize());
//
//		if (page.isOrderBySetted()) {
//			final String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
//			final String[] orderArray = StringUtils.split(page.getOrder(), ',');
//
//			Assert.isTrue(orderByArray.length == orderArray.length, "分页多重排序参数中,排序字段与排序方向的个数不相等");
//
//			for (int i = 0; i < orderByArray.length; i++) {
//				if (Page.ASC.equals(orderArray[i])) {
//					c.addOrder(Order.asc(orderByArray[i]));
//				} else {
//					c.addOrder(Order.desc(orderByArray[i]));
//				}
//			}
//		}
//		return c;
//	}

	/**
	 * 执行count查询获得本次Hql查询所能获得的对象总数.
	 * 
	 * 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
	 */
	protected long countQlResult(final String ql, final Object... values) {
		final String countQl = this.prepareCountQl(ql);

		try {
			final Long count = this.findUnique(countQl, values);
			return count;
		} catch (final Exception e) {
			throw new RuntimeException("ql can't be auto count, ql is:" + countQl, e);
		}
	}

	/**
	 * 执行count查询获得本次Hql查询所能获得的对象总数.
	 * 
	 * 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
	 */
	protected long countQlResult(final String ql, final Map<String, ?> values) {
		final String countQl = this.prepareCountQl(ql);

		try {
			final Long count = this.findUnique(countQl, values);
			
			return count;
		} catch (final Exception e) {
			throw new RuntimeException("ql can't be auto count, ql is:" + countQl, e);
		}
	}

	private String prepareCountQl(final String orgQl) {
		String fromQl = orgQl;
		
		// select子句与order by子句会影响count查询,进行简单的排除.
		fromQl = "from " + StringUtils.substringAfter(fromQl, "from");
		fromQl = StringUtils.substringBefore(fromQl, "order by");

		final String countQl = "select count(*) " + fromQl;
		return countQl;
	}

//	/**
//	 * 执行count查询获得本次Criteria查询所能获得的对象总数.
//	 */
//	@SuppressWarnings("unchecked")
//	protected long countCriteriaResult(final Criteria c) {
//		final CriteriaImpl impl = (CriteriaImpl) c;
//
//		// 先把Projection、ResultTransformer、OrderBy取出来,清空三者后再执行Count操作
//		final Projection projection = impl.getProjection();
//		final ResultTransformer transformer = impl.getResultTransformer();
//
//		List<CriteriaImpl.OrderEntry> orderEntries = null;
//		try {
//			orderEntries = (List) ReflectionUtils.getFieldValue(impl, "orderEntries");
//			ReflectionUtils.setFieldValue(impl, "orderEntries", new ArrayList());
//		} catch (final Exception e) {
//			this.logger.error("不可能抛出的异常:{}", e);
//		}
//
//		// 执行Count查询
//		final Long totalCountObject = (Long) c.setProjection(Projections.rowCount()).uniqueResult();
//		final long totalCount = (totalCountObject != null) ? totalCountObject : 0;
//
//		// 将之前的Projection,ResultTransformer和OrderBy条件重新设回去
//		c.setProjection(projection);
//
//		if (projection == null) {
//			c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
//		}
//		if (transformer != null) {
//			c.setResultTransformer(transformer);
//		}
//		try {
//			ReflectionUtils.setFieldValue(impl, "orderEntries", orderEntries);
//		} catch (final Exception e) {
//			this.logger.error("不可能抛出的异常:{}", e);
//		}
//		return totalCount;
//	}
}
